import axios from 'axios'; // 引入axios
import QS from 'qs'; // 引入qs模块，用来序列化post类型的数据，后面会提到

import { Toast, Dialog } from 'vant';
import store from "@/store/index";
import i18n from '@/i18n';
import router from '@/router/router'
import { signatureGenerate } from "@/utils/signatureUtil"
import {decryptText, encryptText, objectToQueryString} from "@/utils/aes"
import {isMobile} from "@/utils/utis";
import {generateFingerprint} from "@/utils/generateFingerprint";
let deviceStr = `deviceType=H5&physicalId=${generateFingerprint()}`

class AxiosRequest {
  /**
   * @description Class AxiosRequest constructor.
   * @param {String} baseUrl Request base url.
   * @param {Object} headers Request headers config.
   * @param {Boolean} isLoading Request loading switch.
   */
  constructor(baseUrl, headers, isLoading) {
    this.baseUrl = baseUrl;
    this.headers = headers;
    this.isLoading = isLoading;
    this.queue = {};
  }

  /**
   * @description Get inside config.
   * @returns Inside config.
   */
  getInsideConfig() {
    const config = {
      // alert: Axios default base url param is "baseURL" not is "baseUrl" !
      baseURL: this.baseUrl,
      headers: this.headers,
      timeout: 10000
    }
    return config;
  }

  /**
   * @description Destroy completed request.
   * @param {String} url The completed request.
   */
  destroy(url) {
    delete this.queue[url];
    if (!Object.keys(this.queue).length) {
      // Present request complete.
      // Remove request loading.
      if (this.isLoading) {
        Toast.clear();
      }
    }
  }

  /**
   * @description The axios intercept.
   * @param {Function} instance Create axios get instance.
   * @param {String} url Request url.
   */
  interceptors(instance, url) {
    // Request intercept.
    instance.interceptors.request.use(
        config => {
          if (!Object.keys(this.queue).length) {
            if (this.isLoading) {
              // Add request loading.
              Toast.loading({
                duration: 0,
                forbidClick: true,
                loadingType: "spinner",
                message: i18n.t('加载中...')
              });
            }
            this.queue[url] = true;
          }
          var token = store.state.user.userInfo.token
          // console.log('111',config.data)
          //加密传参
          let nowStr = "";
          if (config.method === 'post') {
            let strArr = [] //参数集合
            if (config.data instanceof Object) {
              strArr = strArr.concat(
                  Object.entries(config.data)
                      .map(([key, value]) => `${key}=${value}`)
              );
            }  
            if(token)
            {
              nowStr = strArr.length>0 ? strArr.join("&")+'&token='+token + '&' + deviceStr :'token='+token + '&' + deviceStr; //拿到传参的参数和值
            }else{
              nowStr = strArr.length>0 ? strArr.join("&") + '&' + deviceStr : deviceStr
            }
            // console.log('11111222',`${nowStr} \n ${config.url}`)
            let str = ''
            //没有参数不加密
            if(nowStr){
              str = `cipherTextKey=${encodeURIComponent(encryptText(nowStr))}`
              config.data=nowStr
            }else {
              config.data=nowStr
            }

          }else{
            if (token) {
              if (!config.params) {
                config.params = {}
              }
              config.params.token = token;
            }
            nowStr = objectToQueryString(config.params);
            config.params = {
              cipherTextKey:encryptText(nowStr)
            }
          }

          //加密传参需再传xcry=true
          config.headers["xcry"] = true;
          //返回加密数据需再传ycry=true,在api配置加上isDecrypt,如果等于 1，则不需要传ycry 接口解密打开下面这个
          // if(config.isDecrypt !== 1){
          //   config.headers["ycry"] = true;
          // }
          // 获取请求头参数
          const { timestamp, signature, systemRandom } = signatureGenerate()
          // 分别将签名、时间戳 至请求头
          if (signature) config.headers["sign"] = signature
          if (timestamp) config.headers["tissuePaper"] = timestamp
          if (systemRandom) config.headers["systemRandom"] = systemRandom
          return config;
        },
        error => {
          if (this.isLoading) {
            Toast.clear();
          }
          return Promise.reject(error);
        }
    );
    // Response intercept.
    instance.interceptors.response.use(
        result => {
          //在api配置加上isDecrypt,如果等于 1，则不需要解密 接口解密打开下面这个
          //let data = result.config.isDecrypt !== 1 ? decryptText(result.data) : result.data
          let data = result.data
          this.destroy(url);
          if (data.code == 0) {
            return data;
          } else if (data.code == 401) {
            Dialog.confirm({
              confirmButtonText: i18n.t('确定'),
              cancelButtonText: i18n.t('取消'),
              title: i18n.t('提示'),
              message: i18n.t('未实名认证，是否认证？'),
              beforeClose: (action, done) => {
                if (action === 'confirm') {
                  done();
                  router.push({
                    path: '/authentication'
                  });
                } else {
                  done();
                }
              },
            });
            return data;
          } else if (data.code == 403||data.code == 297 || data.code == 214 || data.code == 213) {
            router.replace({
              path: '/login',
              query: {
                redirect: router.currentRoute.fullPath
              }
            });
            localStorage.removeItem("verifyData");
            store.commit('user/SET_OUT');
          } else {
            if (data.msg != undefined) {
              if(result.config.url ==='/api/user!addAddressBook.action'){
                Toast().clear()
              }else{
                Toast.fail(i18n.t(data.msg));
              }
            }
            return Promise.reject(data);
          }
        },
        error => {
          if (this.isLoading) {
            Toast.clear();
          }
          if (error.code == 'ERR_NETWORK') {
            Toast({ message: 'ERR_NETWORK', type: 'fail', duration: 1000 })
          } else if (error.code == 'ECONNABORTED') {
            //Toast({ message: 'Network Timeout', type: 'fail', duration: 2000 })
            return Promise.reject(error);
          }
          // if (error.message.includes("timeout")) {
          //   Toast.fail(i18n.t("网络超时！"));
          // }
          return Promise.reject(error);
        }
    );
  }

  /**
   * @description Axios request function.
   * @param {Object} options Axios request options.
   * @returns Create axios get instance.
   */
  request(options) {
    const instance = axios.create();
    options = Object.assign(this.getInsideConfig(), options);
    this.interceptors(instance, options.url);
    return instance(options);
  }
}

export default AxiosRequest;
